package com.cee.quartz.component;

import java.util.Date;

import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Service
public class QuartzUtil {

    public final Logger logger = LoggerFactory.getLogger(QuartzUtil.class);

    @Autowired
    private Scheduler scheduler;

    /**
     * get JobDetail
     * @param jobName
     * @param jobGroupName
     * @return JobDetail
     */
    public JobDetail getJobDetail(String jobName, String jobGroupName) throws SchedulerException {
        JobDetail jobDetail = scheduler.getJobDetail(new JobKey(jobName, jobGroupName));
        return jobDetail;
    }

    public synchronized void pauseAll() throws SchedulerException {
        try {
            scheduler.pauseAll();
            logger.info("pauseAll Success!");
        } catch (SchedulerException e) {
            logger.error("pauseAll", e);
            throw new SchedulerException("pauseAll", e);
        }
    }

    public synchronized void resumeAll() throws SchedulerException {
        try {
            scheduler.resumeAll();
            logger.info("resumeAll Success!");
        } catch (SchedulerException e) {
            logger.error("resumeAll", e);
            throw new SchedulerException("resumeAll", e);
        }
    }

    public synchronized void deleteJob(String jobName, String jobGroup) throws SchedulerException {
        logger.info("deleteJob JobName {},jobGroup {},", jobName, jobGroup);
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (jobKey != null) {
                scheduler.deleteJob(jobKey);
            } else {
                throw new SchedulerException("JobName : " + jobName + ", jobGroup : " + jobGroup + ", JobKey is Null!");
            }
            logger.info("deleteJob Success!");
        } catch (SchedulerException e) {
            logger.error("deleteJob", e);
            throw new SchedulerException("deleteJob", e);
        }
    }

    /**
     * When restart according to pause time to make up the function of this period of time required to perform
     *
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public synchronized void pauseJob(String jobName, String jobGroup) throws SchedulerException {
        logger.info("pauseJob JobName {},jobGroup {},", jobName, jobGroup);
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (jobKey != null) {
                scheduler.pauseJob(jobKey);
            } else {
                throw new SchedulerException("JobName : " + jobName + ", jobGroup : " + jobGroup + ", JobKey is Null!");
            }
            logger.info("pauseJob Success!");
        } catch (SchedulerException e) {
            logger.error("pauseJob", e);
            throw new SchedulerException("pauseJob", e);
        }
    }

    /**
     * resume job
     *
     * @param jobName
     * @param jobGroup
     * @throws SchedulerException
     */
    public synchronized void resumeJob(String jobName, String jobGroup) throws SchedulerException {
        logger.info("resumeJob JobName {},jobGroup {},", jobName, jobGroup);
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (jobKey != null) {
                scheduler.resumeJob(jobKey);
            } else {
                throw new SchedulerException("JobName : " + jobName + ", jobGroup : " + jobGroup + ", JobKey is Null!");
            }
            logger.info("resumeJob Success!");
        } catch (SchedulerException e) {
            logger.error("resumeJob", e);
            throw new SchedulerException("resumeJob", e);
        }
    }

    public synchronized void addOrUpdateJob(String jobName, String jobGroup, String description, String cronExpression, Class<? extends Job> beanClass, JobDataMap jobData) throws SchedulerException {
        logger.info("add or update Job(scheduleJob) JobName {}, jobGroup {}, cronExpression {}, beanClass {}, jobData {}", jobName, jobGroup, cronExpression, beanClass, jobData);
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (null == trigger) {
                JobBuilder jobBuilder = JobBuilder.newJob(beanClass).withIdentity(jobName, jobGroup).withDescription(description);
                if (jobData != null) {
                    jobBuilder = jobBuilder.setJobData(jobData);
                }
                JobDetail jobDetail = jobBuilder.storeDurably(true).build();// 任务名称和组构成任务key
                trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).startNow().build();
                scheduler.scheduleJob(jobDetail, trigger);
                scheduler.start();
                logger.info("addJob Success");
            } else {
                if (trigger.getJobDataMap() != null) {
                    CronTrigger finalTrigger = trigger;
                    jobData.forEach((key, value) -> {
                        finalTrigger.getJobDataMap().put(key, value);
                        logger.info("{}={}", key, value);
                    });
                }
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).startNow().build();
                scheduler.rescheduleJob(triggerKey, trigger);
                logger.info("rescheduleJob Success");
            }

        } catch (SchedulerException e) {
            logger.error("addJob(scheduleJob) fail", e);
            throw new SchedulerException("addJob", e);
        }
    }

   /*
    @SuppressWarnings("unchecked")
    public void invokMethod(String jobName) {
        Object object = null;
        Class<? extends Job> clazz = null;
        if (null !=scheduleJob.getBeanClass()) {
            try {
                clazz = (Class<? extends Job>) Class.forName(scheduleJob.getBeanClass());
                object = clazz.newInstance();
            } catch (Exception e) {
                log.error("invokMethod", e);
                e.printStackTrace();
            }
        }
        if (object == null) {
            log.error("JOBNAME = [" + jobName + "]---------------Could not startup, please check the configuration!");
            return;
        }
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(scheduleJob.getMethodName());
        } catch (NoSuchMethodException e) {
            log.error("JobName = [" + jobName + "]---------------Could not startup, please check the configuration!");
        } catch (SecurityException e) {
            log.error("invokMethod", e);
            e.printStackTrace();
        }
        if (method != null) {
            try {
                method.invoke(object);
            } catch (IllegalAccessException e) {
                log.error("invokMethod", e);
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                log.error("invokMethod", e);
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                log.error("invokMethod", e);
                e.printStackTrace();
            }
        }

    }*/

    /**
     * find the runtime job
     * @return
     * @throws Exception
     *//*
    public synchronized List<EventJobDetailDTO> getJobRunning() throws SchedulerException{
        List<JobExecutionContext> executingJobs = schedule.getCurrentlyExecutingJobs();
        List<EventJobDetailDTO> jobList = new ArrayList<EventJobDetailDTO>(executingJobs.size());
        try{
            for (JobExecutionContext executingJob : executingJobs) {
                EventJobDetailDTO job = new EventJobDetailDTO();
                JobDetail jobDetail = executingJob.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = executingJob.getTrigger();
                job.setJobName(jobKey.getName());
                job.setJobGroup(jobKey.getGroup());
                job.setDescription("scheduleTriggerKey:" + trigger.getKey());
                Trigger.TriggerState triggerState = schedule.getTriggerState(trigger.getKey());
                job.setJobStatus(triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCronExpression(cronExpression);
                }
                jobList.add(job);
            }
        }catch (SchedulerException e) {
            log.error("getJobRunning", e);
            throw new SchedulerException("getJobRunning fail",e);
        }
        return jobList;
    }*/

    /**
     * run once job(ok)
     */
    public synchronized void runJob(String jobName, String jobGroup) throws SchedulerException {
        logger.info("runJob JobName {},jobGroup {},", jobName, jobGroup);
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (jobKey != null) {
                scheduler.triggerJob(jobKey);
            } else {
                throw new SchedulerException("JobName : " + jobName + ", jobGroup : " + jobGroup + ", JobKey is Null!");
            }
            logger.info("runJob JobName Success");
        } catch (SchedulerException e) {
            logger.error("runJob", e);
            throw new SchedulerException("runJob", e);
        }
    }
}
